package drds.plus.executor.cursor.cursor_factory;

import drds.plus.common.model.RepositoryType;
import drds.plus.common.properties.ConnectionProperties;
import drds.plus.executor.ExecuteContext;
import drds.plus.executor.cursor.cursor.*;
import drds.plus.executor.cursor.cursor.impl.AggregateCursor;
import drds.plus.executor.cursor.cursor.impl.ColumnAliasCursor;
import drds.plus.executor.cursor.cursor.impl.SortingCursor;
import drds.plus.executor.cursor.cursor.impl.common.*;
import drds.plus.executor.cursor.cursor.impl.join.IndexBlockNestedtLoopCursor;
import drds.plus.executor.cursor.cursor.impl.join.IndexNestedLoopMgetImpCursor;
import drds.plus.executor.cursor.cursor.impl.join.SortMergeJoinCursor;
import drds.plus.executor.cursor.cursor.impl.merge.MergeCursor;
import drds.plus.executor.cursor.cursor.impl.result_cursor.ResultCursor;
import drds.plus.executor.cursor.cursor.impl.sort.SortCursor;
import drds.plus.executor.cursor.cursor.impl.sort.SortedMergeCursors;
import drds.plus.executor.cursor.cursor.impl.sort.TemporaryTableCursor;
import drds.plus.executor.cursor.cursor.impl.sort.TemporaryTableSortCursor;
import drds.plus.executor.cursor.cursor_metadata.CursorMetaData;
import drds.plus.executor.data_node_executor.DataNodeExecutorContext;
import drds.plus.executor.repository.Repository;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Query;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.Item;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.column.Column;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Filter;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Function;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Operation;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import drds.plus.util.ExtraCmd;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 默认的cursor工厂
 */

public class CursorFactoryImpl implements CursorFactory {

    public CursorFactoryImpl() {
        super();
    }

    protected void closeParentCursor(Cursor parentCursor) {
        if (parentCursor != null) {
            List<RuntimeException> exs = new ArrayList();
            exs = parentCursor.close(exs);
            if (!exs.isEmpty())
                throw new RuntimeException(exs.get(0));

        }
    }

    public IAggregateCursor aggregateCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<Function> aggregates, List<OrderBy> groupByList, boolean isMerge) throws RuntimeException {
        try {
            return new AggregateCursor(executeContext, sortingCursor, aggregates, groupByList, isMerge);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public IColumnAliasCursor columnAliasCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<Item> retColumns, String name) throws RuntimeException {
        try {
            return new ColumnAliasCursor(sortingCursor, retColumns, name);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public ValueFilterCursor valueFilterCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, Filter filter) throws RuntimeException {
        try {
            return new ValueFilterCursor(executeContext, sortingCursor, filter);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public SortCursor mergeSortedCursor(ExecuteContext executeContext, List<ISortingCursor> sortingCursorList, boolean duplicated) throws RuntimeException {
        try {
            return new SortedMergeCursors(sortingCursorList, duplicated);
        } catch (Exception e) {
            for (ISortingCursor cursor : sortingCursorList) {
                closeParentCursor(cursor);
            }

            throw new RuntimeException(e);
        }
    }

    public ITemporaryTableSortCursor temporaryTableSortCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<OrderBy> orderByList, boolean sortedDuplicates, long requestId) throws RuntimeException {
        try {
            if (ExtraCmd.getExtraCmdBoolean(executeContext.getExtraCmds(), ConnectionProperties.ALLOW_TEMPORARY_TABLE, false)) {

                Repository repository = DataNodeExecutorContext.getExecutorContext().getRepositoryNameToRepositoryMap().getRepository(RepositoryType.bdb.name(), Collections.EMPTY_MAP, executeContext.getExtraCmds());
                return new TemporaryTableSortCursor(executeContext, this, repository, requestId, sortingCursor, orderByList, sortedDuplicates);
            }

            throw new IllegalStateException("not allow to use temporary where . allow firstInNewCursor");

        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public TemporaryTableCursor temporaryTableCursor(ExecuteContext executeContext, Query query, List<OrderBy> orderByList, boolean sortedDuplicates, long requestId) throws RuntimeException {

        Repository repository = DataNodeExecutorContext.getExecutorContext().getRepositoryNameToRepositoryMap().getRepository(RepositoryType.bdb.name(), Collections.EMPTY_MAP, executeContext.getExtraCmds());
        return new TemporaryTableCursor(executeContext, repository, requestId, query, sortedDuplicates);

    }

    public TemporaryTableCursor temporaryTableCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<OrderBy> orderByList, boolean sortedDuplicates, long requestId) throws RuntimeException {
        try {

            Repository repository = DataNodeExecutorContext.getExecutorContext().getRepositoryNameToRepositoryMap().getRepository(RepositoryType.bdb.name(), Collections.EMPTY_MAP, executeContext.getExtraCmds());
            return new TemporaryTableCursor(executeContext, repository, requestId, sortingCursor, orderByList, sortedDuplicates);

        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public IReverseOrderByCursor reverseOrderCursor(ExecuteContext executeContext, ISortingCursor sortingCursor) throws RuntimeException {
        try {
            return new ReverseOrderByCursor(sortingCursor);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public IMergeCursor mergeCursor(ExecuteContext executeContext, MergeQuery mergeQuery, List<ISortingCursor> sortingCursorList) throws RuntimeException {
        try {
            return new MergeCursor(executeContext, mergeQuery, sortingCursorList);
        } catch (Exception e) {
            if (sortingCursorList != null) {
                for (ISortingCursor iSortingCursor : sortingCursorList) {
                    closeParentCursor(iSortingCursor);
                }
            }
            throw new RuntimeException(e);
        }
    }

    public IIndexNestLoopCursor indexNestLoopCursor(ExecuteContext executeContext, Join join,//
                                                    ISortingCursor leftSideCursor, List leftSideJoinItemList, //
                                                    ISortingCursor rightSideCursor, List rightSideJoinItemList) throws RuntimeException {//
        try {
            return new IndexNestedLoopMgetImpCursor(executeContext, join, //
                    leftSideCursor, leftSideJoinItemList, rightSideCursor,//
                    rightSideJoinItemList);//
        } catch (Exception e) {
            closeParentCursor(leftSideCursor);
            closeParentCursor(rightSideCursor);
            throw new RuntimeException(e);
        }
    }

    public ILimitFromToCursor limitFromToCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, Long limitFrom, Long limitTo) throws RuntimeException {
        try {
            return new LimitFromToCursor(sortingCursor, limitFrom, limitTo);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public IMergeSortJoinCursor sortMergeJoinCursor(ExecuteContext executeContext, Join join, ISortingCursor leftCursor, List leftJoinColumnList, ISortingCursor rightCursor, List rightJoinColumnList) throws RuntimeException {
        try {

            return new SortMergeJoinCursor(join, leftCursor, rightCursor, leftJoinColumnList, rightJoinColumnList);
        } catch (Exception e) {
            closeParentCursor(leftCursor);
            closeParentCursor(rightCursor);
            throw new RuntimeException(e);
        }
    }

    public AffectRowCursor affectRowCursor(ExecuteContext executeContext, int affectRow) {
        return new AffectRowCursor(affectRow);
    }

    public ISortingCursor schematicCursor(ExecuteContext executeContext, Cursor cursor, CursorMetaData cursorMetaData, List<OrderBy> orderByList) throws RuntimeException {
        try {
            return new SortingCursor(cursor, cursorMetaData, orderByList);
        } catch (Exception e) {
            closeParentCursor(cursor);
            throw new RuntimeException(e);
        }
    }

    public IInCursor inCursor(ExecuteContext executeContext, Cursor cursor, List<OrderBy> orderByList, Column column, List<Object> valueList, Operation operation) {
        return new InCursor(cursor, orderByList, column, valueList, operation);
    }

    public IMergeCursor mergeCursor(ExecuteContext executeContext, MergeQuery mergeQuery, List<ISortingCursor> sortingCursorList, CursorMetaData cursorMetaData, List<OrderBy> orderByList) throws RuntimeException {
        try {
            return new MergeCursor(executeContext, mergeQuery, sortingCursorList, orderByList, cursorMetaData);
        } catch (Exception e) {
            if (sortingCursorList != null) {
                for (ISortingCursor iSortingCursor : sortingCursorList) {
                    closeParentCursor(iSortingCursor);
                }
            }
            throw new RuntimeException(e);
        }
    }

    public IIndexBlockNestedLoopCursor indexBlockNestedLoopCursor(ExecuteContext executeContext, Join join, ISortingCursor leftCursor, List leftJoinColumnList, ISortingCursor rightCursor, List rightJoinColumnList, List columns) throws RuntimeException {

        try {
            return new IndexBlockNestedtLoopCursor(executeContext, this, join, leftCursor, leftJoinColumnList, rightCursor, rightJoinColumnList);
        } catch (Exception e) {
            closeParentCursor(leftCursor);
            closeParentCursor(rightCursor);
            throw new RuntimeException(e);
        }
    }

    public IRangeCursor rangeCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, Filter filter) throws RuntimeException {
        try {
            return new RangeCursor(executeContext, sortingCursor, filter);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public ISetOrderByListCursor setOrderByListCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<OrderBy> orderByListInRequest) throws RuntimeException {
        try {
            return new SetOrderByListCursor(sortingCursor, null, orderByListInRequest);
        } catch (Exception e) {
            closeParentCursor(sortingCursor);
            throw new RuntimeException(e);
        }
    }

    public ResultCursor resultCursor(ExecuteContext executeContext, ISortingCursor sortingCursor, List<Object> retColumns) throws RuntimeException {
        return new ResultCursor(executeContext, sortingCursor, retColumns);
    }

}
